]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/Tests/Unit Tests/SuspiciousReplyTest.m
mDNSResponder-1096.40.7.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / Tests / Unit Tests / SuspiciousReplyTest.m
1 /*
2 * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "unittest_common.h"
18 #import <XCTest/XCTest.h>
19
20 struct UDPSocket_struct
21 {
22 mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
23 };
24 typedef struct UDPSocket_struct UDPSocket;
25
26 // This client request was generated using the following command: "dns-sd -Q 123server.dotbennu.com. A".
27 uint8_t test_query_client_msgbuf[35] = {
28 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65,
29 0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00,
30 0x01, 0x00, 0x01
31 };
32
33 // This uDNS message is a canned response that was originally captured by wireshark.
34 uint8_t test_query_response_msgbuf[108] = {
35 0x69, 0x41, // transaction id
36 0x85, 0x80, // flags
37 0x00, 0x01, // 1 question for 123server.dotbennu.com. Addr
38 0x00, 0x02, // 2 anwsers: 123server.dotbennu.com. CNAME test212.dotbennu.com., test212.dotbennu.com. Addr 10.100.0.1,
39 0x00, 0x01, // 1 authorities anwser: dotbennu.com. NS cardinal2.apple.com.
40 0x00, 0x00, 0x09, 0x31, 0x32, 0x33,
41 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x08, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x03,
42 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
43 0x02, 0x56, 0x00, 0x0a, 0x07, 0x74, 0x65, 0x73, 0x74, 0x32, 0x31, 0x32, 0xc0, 0x16, 0xc0, 0x34,
44 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x04, 0x0a, 0x64, 0x00, 0x01, 0xc0, 0x16,
45 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x12, 0x09, 0x63, 0x61, 0x72, 0x64, 0x69,
46 0x6e, 0x61, 0x6c, 0x32, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x65, 0xc0, 0x1f
47 };
48
49 // Variables associated with contents of the above uDNS message
50 #define uDNS_TargetQID 16745
51 char test_original_domainname_cstr[] = "123server.dotbennu.com.";
52 char test_cname_domainname_cstr[] = "test212.dotbennu.com.";
53
54 @interface SuspiciousReplyTest : XCTestCase
55 {
56 UDPSocket* local_socket;
57 request_state* client_request_message;}
58 @end
59
60 @implementation SuspiciousReplyTest
61
62 // The InitThisUnitTest() initializes the mDNSResponder environment as well as
63 // a DNSServer. It also allocates memory for a local_socket and client request.
64 // Note: This unit test does not send packets on the wire and it does not open sockets.
65 - (void)setUp
66 {
67 mDNSPlatformMemZero(&mDNSStorage, sizeof(mDNS));
68
69 // Init unit test environment and verify no error occurred.
70 mStatus result = init_mdns_environment(mDNStrue);
71 XCTAssertEqual(result, mStatus_NoError);
72
73 // Add one DNS server and verify it was added.
74 AddDNSServer_ut();
75 XCTAssertEqual(CountOfUnicastDNSServers(&mDNSStorage), 1);
76
77 // Create memory for a socket that is never used or opened.
78 local_socket = (UDPSocket *) mDNSPlatformMemAllocateClear(sizeof(*local_socket));
79
80 // Create memory for a request that is used to make this unit test's client request.
81 client_request_message = calloc(1, sizeof(request_state));
82 }
83
84 - (void)tearDown
85 {
86 mDNS *m = &mDNSStorage;
87 request_state* req = client_request_message;
88 DNSServer *ptr, **p = &m->DNSServers;
89
90 while (req->replies)
91 {
92 reply_state *reply = req->replies;
93 req->replies = req->replies->next;
94 mDNSPlatformMemFree(reply);
95 }
96 mDNSPlatformMemFree(req);
97
98 mDNSPlatformMemFree(local_socket);
99
100 while (*p)
101 {
102 ptr = *p;
103 *p = (*p)->next;
104 LogInfo("FinalizeUnitTest: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
105 mDNSPlatformMemFree(ptr);
106 }
107 }
108
109 - (void)testSuspiciousReplyTestSeries
110 {
111 [self _clientQueryRequest];
112 [self _verifySuspiciousResponseBehavior];
113 }
114
115 // Simulate a uds client request by setting up a client request and then
116 // calling mDNSResponder's handle_client_request. The handle_client_request function
117 // processes the request and starts a query. This unit test verifies
118 // the client request and query were setup as expected. This unit test also calls
119 // mDNS_execute which determines the cache does not contain the new question's
120 // answer.
121 - (void)_clientQueryRequest
122 {
123 mDNS *const m = &mDNSStorage;
124 request_state* req = client_request_message;
125 char *msgptr = (char *)test_query_client_msgbuf;
126 size_t msgsz = sizeof(test_query_client_msgbuf);
127 mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
128 DNSQuestion *q;
129 mStatus err = mStatus_NoError;
130 char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
131
132 // Process the unit test's client request
133 start_client_request(req, msgptr, msgsz, query_request, local_socket);
134 XCTAssertEqual(err, mStatus_NoError);
135
136 // Verify the request fields were set as expected
137 XCTAssertNil((__bridge id)req->next);
138 XCTAssertNil((__bridge id)req->primary);
139 XCTAssertEqual(req->sd, client_req_sd);
140 XCTAssertEqual(req->process_id, client_req_process_id);
141 XCTAssertFalse(strcmp(req->pid_name, client_req_pid_name));
142 XCTAssertEqual(req->validUUID, mDNSfalse);
143 XCTAssertEqual(req->errsd, 0);
144 XCTAssertEqual(req->uid, client_req_uid);
145 XCTAssertEqual(req->ts, t_complete);
146 XCTAssertGreaterThan((mDNSs32)req->data_bytes, min_size);
147 XCTAssertEqual(req->msgend, msgptr+msgsz);
148 XCTAssertNil((__bridge id)(void*)req->msgbuf);
149 XCTAssertEqual(req->hdr.version, VERSION);
150 XCTAssertNil((__bridge id)req->replies);
151 XCTAssertNotEqual(req->terminate, (req_termination_fn)0);
152 XCTAssertEqual(req->flags, kDNSServiceFlagsReturnIntermediates);
153 XCTAssertEqual(req->interfaceIndex, kDNSServiceInterfaceIndexAny);
154
155 // Verify the query fields were set as expected
156 q = &req->u.queryrecord.op.q;
157 XCTAssertNotEqual(q, (DNSQuestion *)mDNSNULL);
158 XCTAssertEqual(q, m->Questions);
159 XCTAssertEqual(q, m->NewQuestions);
160 XCTAssertEqual(q->SuppressUnusable, mDNSfalse);
161 XCTAssertEqual(q->ReturnIntermed, mDNStrue);
162 XCTAssertEqual(q->Suppressed, mDNSfalse);
163
164 ConvertDomainNameToCString(&q->qname, qname_cstr);
165 XCTAssertFalse(strcmp(qname_cstr, test_original_domainname_cstr));
166 XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname));
167
168 XCTAssertEqual(q->InterfaceID, mDNSInterface_Any);
169 XCTAssertEqual(q->flags, req->flags);
170 XCTAssertEqual(q->qtype, 1);
171 XCTAssertEqual(q->qclass, 1);
172 XCTAssertEqual(q->LongLived, 0);
173 XCTAssertEqual(q->ExpectUnique, mDNSfalse);
174 XCTAssertEqual(q->ForceMCast, 0);
175 XCTAssertEqual(q->TimeoutQuestion, 0);
176 XCTAssertEqual(q->WakeOnResolve, 0);
177 XCTAssertEqual(q->UseBackgroundTraffic, 0);
178 XCTAssertEqual(q->ValidationRequired, 0);
179 XCTAssertEqual(q->ValidatingResponse, 0);
180 XCTAssertEqual(q->ProxyQuestion, 0);
181 XCTAssertNotEqual((void*)q->QuestionCallback, (void*)mDNSNULL);
182 XCTAssertNil((__bridge id)q->DNSSECAuthInfo);
183 XCTAssertNil((__bridge id)(void*)q->DAIFreeCallback);
184 XCTAssertEqual(q->AppendSearchDomains, 0);
185 XCTAssertNil((__bridge id)q->DuplicateOf);
186
187 // Call mDNS_Execute to see if the new question, q, has an answer in the cache.
188 // It won't be yet because the cache is empty.
189 m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
190 mDNS_Execute(m);
191
192 // Verify mDNS_Execute processed the new question.
193 XCTAssertNil((__bridge id)m->NewQuestions);
194
195 // Verify the cache is empty and the request got no reply.
196 XCTAssertEqual(m->rrcache_totalused, 0);
197 XCTAssertNil((__bridge id)req->replies);
198 }
199
200 // This unit test tries to receive a response but changes the QID so it is ignored and can trigger suspicious mode
201 // 1) Test a suspicious response is ignored, but if it was previously requested, then don't go into suspicious mode
202 // 2) Test a suspicious response is ignored, and it does trigger suspicious mode
203 // 3) Test a configuration change event will reset suspicious mode
204 - (void)_verifySuspiciousResponseBehavior
205 {
206 mDNS *const m = &mDNSStorage;
207 DNSMessage *msgptr = (DNSMessage *)test_query_response_msgbuf;
208 size_t msgsz = sizeof(test_query_response_msgbuf);
209 request_state* req = client_request_message;
210 mDNSOpaque16 suspiciousQID;
211
212 // 1)
213 // Receive and verify it is suspicious (ignored response)
214 // But not too suspicious (did NOT go into suspicious mode)
215
216 suspiciousQID.NotAnInteger = 0xDEAD;
217 receive_suspicious_response_ut(req, msgptr, msgsz, suspiciousQID, true);
218
219 // Verify 0 records recevied
220 mDNSu32 CacheUsed =0, notUsed =0;
221 LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, &notUsed);
222 XCTAssertEqual(CacheUsed, 0); // Verify 0 records recevied
223 XCTAssertFalse(m->NextSuspiciousTimeout); // And NOT in suspicious mode
224
225 // 2)
226 // Receive and verify it is suspicious (ignored response)
227 // And put itself in suspicious mode (did go into suspicious mode)
228
229 receive_suspicious_response_ut(req, msgptr, msgsz, suspiciousQID, false);
230 LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, &notUsed);
231 XCTAssertEqual(CacheUsed, 0); // Verify 0 records recevied
232 XCTAssertTrue(m->NextSuspiciousTimeout); // And IS in suspicious mode
233
234 // 3)
235 // Verify suspicious mode is stopped when a configuration change occurs.
236
237 force_uDNS_SetupDNSConfig_ut(m);
238 XCTAssertFalse(m->NextSuspiciousTimeout);
239 }
240
241
242 @end